<script setup lang="ts">
import VisibleObserver from "./visible-observer.vue";
import { computed, type CSSProperties, nextTick, onUnmounted, type PropType, ref, shallowRef, watch } from "vue";
import type { EchartsPlotRef } from "./echarts-plot-types";
import { useWindowResizeTimeout } from "@/framework/vue/hooks";
import * as echarts from "echarts";

defineOptions({ name: "echarts-plot" });
const props = defineProps({
  theme: { type: [String, Object] },
  initOpts: { type: Object as PropType<echarts.EChartsInitOpts> },
  defaultOptions: { type: Object as PropType<echarts.EChartsOption> },
  options: { type: Object as PropType<echarts.EChartsOption> },
  resizeTimeout: { type: Number, default: 500 },
  overflow: { type: String as PropType<CSSProperties["overflow"]>, default: "auto" },
});

const emits = defineEmits({
  ready: () => true,
});

const chart = shallowRef<echarts.EChartsType>();
const chartInstance = computed(() => chart.value!);
const chartEl = shallowRef<HTMLDivElement>();
const isVisible = ref(false);

defineExpose({
  getInstance: () => chart.value!,
  getOption: () => chart.value!.getOption(),
  setOption: (...args: Parameters<echarts.EChartsType["setOption"]>) => chart.value?.setOption(...args),
  dispatchAction: (payload: echarts.Payload, opt?: boolean | { silent?: boolean; flush?: boolean | undefined }) =>
    chart.value?.dispatchAction(payload, opt),
  resize: (opts?: echarts.ResizeOpts) => chart.value?.resize(opts),
  reset(opts?: echarts.EChartsOption) {
    if (chart.value) {
      chart.value.clear();
      if (opts) chart.value.setOption(opts);
    }
  },
} as EchartsPlotRef);

function onVisibleChange(visible: boolean) {
  isVisible.value = visible;
  nextTick(() => {
    if (visible) {
      if (chart.value) {
        chart.value.resize();
      } else {
        initChart();
      }
    }
  });
}

function initChart() {
  const inst = echarts.init(chartEl.value!, props.theme, props.initOpts);
  if (props.defaultOptions != undefined) {
    inst.setOption(props.defaultOptions, { lazyUpdate: true });
  }
  if (props.options != undefined) {
    inst.setOption(props.options);
  }
  chart.value = inst;
  emits("ready");
}

watch(
  () => props.options,
  value => value && chart.value?.setOption(value),
);

useWindowResizeTimeout(props.resizeTimeout, () => isVisible.value && chart.value?.resize());
onUnmounted(() => {
  chart.value?.dispose();
  chart.value = undefined;
  chartEl.value = undefined;
});
</script>

<template>
  <visible-observer :style="{ overflow: overflow }" @visible-change="onVisibleChange">
    <div ref="chartEl" class="full border-box"></div>
  </visible-observer>
</template>
